package com.ruoyi.pay.service.impl;

import com.alipay.api.*;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.pay.domain.PayConfig;
import com.ruoyi.pay.mapper.PayConfigMapper;
import com.ruoyi.pay.service.AlipayService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;

@Service
public class AlipayServiceImpl implements AlipayService {

    private static final Logger log = LoggerFactory.getLogger(AlipayServiceImpl.class);

    @Autowired
    private Environment config;
    @Autowired
    private PayConfigMapper payConfigMapper;

    private AlipayConfig getAlipayConfig() {
        QueryWrapper<PayConfig> wrapper = new QueryWrapper<>();
        wrapper.eq("is_check", 0);
        PayConfig payConfig = payConfigMapper.selectOne(wrapper);
        AlipayConfig alipayConfig = new AlipayConfig();
        alipayConfig.setServerUrl(payConfig.getServerUrl());
        alipayConfig.setAppId(payConfig.getAppId());
        alipayConfig.setPrivateKey(payConfig.getPrivateKey());
        alipayConfig.setFormat("json");
        alipayConfig.setAlipayPublicKey(payConfig.getAlipayPublicKey());
        alipayConfig.setCharset("UTF-8");
        alipayConfig.setSignType("RSA2");
        return alipayConfig;
    }

    @Override
    @Transactional
    public String tradeCreate(HashMap<String, String> map) throws Exception {
        String type = map.get("payType").toString();
        //执行请求,调用支付宝
        if (type.equals("H5")) {
            String h5Order = createH5Order(map);
            return h5Order;
        } else if (type.equals("APP")) {
            String appOrder = createAppOrder(map);
            return appOrder;
        }
        return null;
    }

    /**
     * 创建app订单
     * @param map
     * @return
     */
    public String createAppOrder(HashMap<String,String> map) throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setOutTradeNo(map.get("orderNo"));
        model.setTotalAmount(map.get("total"));
        model.setSubject(map.get("proName"));
        model.setProductCode("FAST_INSTANT_TRADE_PAY");
        model.setTimeoutExpress(map.get("timeout"));// 设置未付款支付宝交易的超时时间，一旦超时，该笔交易就会自动被关闭。当用户进入支付宝收银台页面（不包括登录页面），会触发即刻创建支付宝交易，此时开始计时。取值范围：1m～15d。m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。
        request.setBizModel(model);
        //支付宝公共参数
        request.setReturnUrl(config.getProperty("alipay.return-url"));
        request.setNotifyUrl(config.getProperty("alipay.notify-url"));
        // 根据不同的产品
        model.setSubject("商品的标题/交易标题/订单标题/订单关键字等");
        AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
        if (response.isSuccess()) {
            log.info("调用成功,返回结果:[{}]",response.getBody());
            return response.getBody();
        } else {
            log.info("调用失败!!");
        }
        return null;
    }

    /**
     * 创建H5订单
     * @param map
     * @return
     */
    public String createH5Order(HashMap<String,String> map) throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        //面向对象封装业务参数
        AlipayTradePagePayModel model =new AlipayTradePagePayModel();
        model.setOutTradeNo(map.get("orderNo"));
        model.setTotalAmount(map.get("total"));
        model.setSubject(map.get("proName"));
        model.setProductCode("FAST_INSTANT_TRADE_PAY");
        model.setTimeoutExpress(map.get("timeout"));// 设置未付款支付宝交易的超时时间，一旦超时，该笔交易就会自动被关闭。当用户进入支付宝收银台页面（不包括登录页面），会触发即刻创建支付宝交易，此时开始计时。取值范围：1m～15d。m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。
        request.setBizModel(model);
        //支付宝公共参数
        request.setReturnUrl(config.getProperty("alipay.return-url"));
        request.setNotifyUrl(config.getProperty("alipay.notify-url"));
        AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
        if (response.isSuccess()) {
            log.info("调用成功,返回结果:[{}]",response.getBody());
            return response.getBody();
        } else {
            log.info("调用失败!!");
        }
        return null;
    }

    @Override
    public String tradeNotify(Map<String, String> params) {
        String result = "failure";
        try {
            //异步通知验签
            boolean signVerified = AlipaySignature.rsaCheckV1(params,
                    config.getProperty("alipay.alipay-public-key"),
                    AlipayConstants.CHARSET_UTF8,
                    AlipayConstants.SIGN_TYPE_RSA2);
            if (!signVerified) {
                // TODO 验签失败则记录异常日志，并在response中返回failure.
                log.error("支付成功,异步通知验签失败!");
                return result;
            }
            log.info("支付成功,异步通知验签成功!");
            //TODO 验签成功后，按照支付结果异步通知中的描述，对支付结果中的业务内容进行二次校验
            //1.验证out_trade_no 是否为商家系统中创建的订单号
            String outTradeNo = params.get("out_trade_no");
            //2.判断 total_amount 是否确实为该订单的实际金额
            String totalAmount = params.get("total_amount");
            //3.校验通知中的 seller_id是否为 out_trade_no 这笔单据的对应的操作方
            String sellerId = params.get("seller_id");
            if (!sellerId.equals(config.getProperty("alipay.seller-id"))) {
                log.error("商家PID校验失败");
                return result;
            }
            //4.验证 app_id 是否为该商家本身
            String appId = params.get("app_id");
            if (!appId.equals(config.getProperty("alipay.app.id"))){
                log.error("app_id校验失败");
                return result;
            }
            //在支付宝的业务通知中，只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时，支付宝才会认定为买家付款成功
            String tradeStatus = params.get("trade_status");
            if (!"TRADE_SUCCESS".equals(tradeStatus) && !"TRADE_FINISHED".equals(tradeStatus)){
                log.error("支付未成功");
                return result;
            }

            //TODO 处理自身业务


            result = "success";
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        return result;
    }
}
